home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Applications / QuArK / quarkpy / mapquakemenu.py < prev    next >
Text File  |  2004-01-05  |  29KB  |  777 lines

  1. """   QuArK  -  Quake Army Knife
  2.  
  3. Implementation of QuArK Map editor's "Quake" menu
  4. """
  5. #
  6. # Copyright (C) 1996-99 Armin Rigo
  7. # THIS FILE IS PROTECTED BY THE GNU GENERAL PUBLIC LICENCE
  8. # FOUND IN FILE "COPYING.TXT"
  9. #
  10.  
  11. #$Header: /cvsroot/quark/runtime/quarkpy/mapquakemenu.py,v 1.37 2003/12/17 13:58:59 peter-b Exp $
  12.  
  13.  
  14.  
  15. import quarkx
  16. from qdictionnary import Strings
  17. from maputils import *
  18. import qmenu
  19. import qquake
  20.  
  21.  
  22. # Constants for BuildCheck extensions!
  23. gExt_GotToExist     = "+"
  24. gExt_MustNotExist   = "-"
  25. gExt_Controllers    = gExt_GotToExist + gExt_MustNotExist
  26. gExt_ValidExtChars  = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  27. gExt_StartOfAction  = "{"
  28. gExt_EndOfAction    = "}"
  29. gExt_ActionFunction = ":"
  30. gExt_SpecialChars   = gExt_StartOfAction + gExt_EndOfAction + gExt_ActionFunction
  31. gExt_AllCharacters  = " " + gExt_Controllers + gExt_ValidExtChars + gExt_SpecialChars
  32.  
  33.  
  34. def CreateCheckFileExtensionArray(instring):
  35.  
  36.     def FindSingleExtension(instring):
  37.         # Must start with a 'gExt_Controllers' character!
  38.         if (not instring[:1] in gExt_Controllers):
  39.             return None, None
  40.         # Find next char not in 'gExt_ValidExtChars', or end-of-line
  41.         ext = instring
  42.         for i in range(1, len(instring)):
  43.             if (instring[i] not in gExt_ValidExtChars):
  44.                 ext = instring[0:i]
  45.                 instring = instring[i:]
  46.                 break
  47.         action = None
  48.         if (instring[:1] == gExt_StartOfAction):
  49.             # Unpack action
  50.             for i in range(1, len(instring)):
  51.                 if (instring[i] not in gExt_ValidExtChars):
  52.                     action = instring[1:i]
  53.                     break
  54.         return ext, action
  55.  
  56.     # Remove all unnessary characters
  57.     reducedstring = filter(lambda d: d in gExt_AllCharacters, instring)
  58.     extactionlist = []
  59.     for i in range(0, len(reducedstring)):
  60.         ext, action = FindSingleExtension(reducedstring[i:])
  61.         if (ext is not None):
  62.             extactionlist = extactionlist + [(ext.upper, action)]
  63.     return extactionlist
  64.  
  65.  
  66.  
  67. def ExtensionFromFilter(filter):
  68.     startex = filter.rfind('|*.')
  69.     return filter[startex+2:]
  70.  
  71.  
  72. class BuildPgmConsole(qquake.BatchConsole):
  73.     "StdOut console for programs that build files."
  74.  
  75.     def __init__(self, cmdline, currentdir, bspfile, editor, next):
  76.         qquake.BatchConsole.__init__(self, cmdline, currentdir, next)
  77.  
  78.  
  79.  
  80. class BuildPgmConsole_Advanced(qquake.BatchConsole):
  81.     "StdOut console for programs that build files."
  82.  
  83.     def __init__(self, cmdline, currentdir, bspfile, editor, next, checkextensions):
  84.         qquake.BatchConsole.__init__(self, cmdline, currentdir, next)
  85.         self.editor=editor
  86.         self.checkextensions = checkextensions
  87.         # Remove file-extension
  88.         try:
  89.             self.bspfile_wo_ext = bspfile[:bspfile.rindex(".")]
  90.         except:
  91.             self.bspfile_wo_ext = bspfile
  92.         # Initial check for files with checkextensions
  93.         for ext, action in self.checkextensions:
  94.             try:
  95.                 workfile = self.bspfile_wo_ext + "." + ext[1:]
  96.                 attr = quarkx.getfileattr(workfile)
  97.                 if (attr!=FA_FILENOTFOUND) and (attr&FA_ARCHIVE):
  98.                     quarkx.setfileattr(workfile, attr-FA_ARCHIVE)
  99.             except quarkx.error:
  100.                 pass
  101.  
  102.     def doAction(self, action, ext):
  103.         # This is the place for the actions, that have HARDCODED names!
  104.         if (action is None):
  105.             return
  106.         action = action.upper()
  107.         if (action == "LOADLINFILE"):
  108.             if self.editor is not None:
  109.                 import mapholes
  110. #                debug('loading: '+ self.bspfile_wo_ext+'.'+ext)
  111.                 mapholes.LoadLinFile(self.editor, self.bspfile_wo_ext+'.'+ext)
  112.         elif (action == "LOADPTSFILE"):
  113.             if self.editor is not None:
  114.                 import mapholes
  115.                 mapholes.LoadLinFile(self.editor, self.bspfile_wo_ext+'.'+ext)
  116.         else:
  117.             print "ERROR: Unknown action \"" + action + "\" for extension \"" + ext + "\""
  118.  
  119.     def FileHasContent(self, ext, attr, filename):
  120.         if (ext[:1] != gExt_MustNotExist):
  121.             return 0
  122.         if ((attr==FA_FILENOTFOUND) or not (attr&FA_ARCHIVE)):
  123.             return 0
  124.         if attr!=FA_FILENOTFOUND:
  125.             f=open(filename, "r")
  126.             data = f.readlines()
  127.             for line in data:
  128.                 if line.strip()!='':
  129.                     return 1
  130.         return 0 # not actually necessary because Python functions returns None by default        
  131.  
  132.     def close(self):
  133.         errorfoundandprintet = 0
  134.         for ext, action in self.checkextensions:
  135.             errortext = None
  136.             workfile = self.bspfile_wo_ext + "." + ext[1:]
  137.             attr = quarkx.getfileattr(workfile)
  138.             if ((ext[:1] == gExt_GotToExist) and ((attr==FA_FILENOTFOUND) or not (attr&FA_ARCHIVE))):
  139.                 errortext = "Build failed, because it did not create the (%s) file: " % ext + workfile
  140.             elif self.FileHasContent(ext, attr, workfile):
  141. #            elif ((ext[:1] == gExt_MustNotExist) and ((attr!=FA_FILENOTFOUND) and (attr&FA_ARCHIVE))):
  142.                 errortext = "Build failed, because it created the (%s) file: " % ext + workfile
  143.  
  144.             # Was error found?
  145.             if (errortext is not None):
  146.                 if (not errorfoundandprintet):
  147.                     print "!-!"*26
  148.                     errorfoundandprintet = 1
  149.                 print errortext
  150.                 self.doAction(action, ext[1:])
  151.  
  152.         if (errorfoundandprintet):
  153.             # Error occured!
  154.             quarkx.console()
  155.             del self.next
  156.         else:
  157.             qquake.BatchConsole.close(self)
  158.  
  159.  
  160. class CloseConsole:
  161.     def run(self):
  162.         if self.console:
  163.             print "Finished !"
  164.         quarkx.console(self.console)
  165.  
  166.  
  167.  
  168. def checkfilename(filename):
  169.     filename = filter(lambda c: c in r"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$%'-_@{}~`!#()", filename)
  170.     return filename or Strings[180]
  171.  
  172.  
  173. def writemapfile(root, mapname, selonly, wadfile, hxstr=None):
  174.     saveflags = 0
  175.     if MapOption("IgnoreToBuild"):
  176.         saveflags = saveflags | SO_IGNORETOBUILD
  177. #    if MapOption("DisableEnhTex"):
  178. #        saveflags = saveflags | SO_DISABLEENHTEX
  179.     if MapOption("DisableFPCoord"):
  180.         saveflags = saveflags | SO_DISABLEFPCOORD
  181. #    if MapOption("EnableBrushPrim"):
  182. #        saveflags = saveflags | SO_ENABLEBRUSHPRIM
  183.     if MapOption("UseIntegralVertices"):
  184.          saveflags = saveflags | SO_USEINTEGRALVERTICES
  185.     if selonly:
  186.         saveflags = saveflags | SO_SELONLY
  187.     setup = quarkx.setupsubset()
  188.     mapfiltercode = setup["MapFilter"]
  189.     if mapfiltercode:
  190.         mapext=ExtensionFromFilter(Strings[eval(mapfiltercode)])
  191.     else:
  192.         mapext='.map'
  193.     mapfullname=mapname+mapext
  194.     m = quarkx.newfileobj(mapfullname)
  195.     m.filename = quarkx.outputfile("maps/%s" % mapfullname)
  196.     worldspawn = root.copy(1)   # preserve selection while copying
  197.     m["Root"] = worldspawn.name
  198.     m.setint("saveflags", saveflags)
  199.     m.appenditem(worldspawn)
  200.     if wadfile:
  201.         worldspawn["wad"] = wadfile
  202.     if hxstr:
  203.         m["hxstrings"] = hxstr
  204.     m.savefile()
  205.     return hxstr and m["hxstrings"]
  206.  
  207.  
  208. def filesformap(map):
  209.     setup = quarkx.setupsubset()
  210.     map = "maps/"+map
  211.     mapholes = setup["MapHoles"]
  212.     if not mapholes:
  213.         mapholes = ".lin"
  214.     normal_files = [map+".bsp", map+mapholes]
  215.     e1 = setup["PakExtra1"]
  216.     if e1:
  217.       normal_files = normal_files + [ map + e1 ]
  218.     return normal_files
  219.  
  220.  
  221. #def FirstBuildCmd():
  222. #    setup = quarkx.setupsubset()
  223. #    if setup["FirstBuildCmd"]:
  224. #        return setup["FirstBuildCmd"]
  225. #    else:
  226. #        return "QBSP1"
  227.  
  228.  
  229. def qmenuitem1click(m):
  230.     editor = mapeditor(SS_MAP)
  231.     if editor is None: return
  232.     if m.info["SelOnly"] and not len(editor.layout.explorer.sellist):
  233.         quarkx.msgbox(Strings[223], MT_ERROR, MB_OK)
  234.         return
  235. #    if MapOption("AutoCheckMap", SS_MAP):
  236. #        setup = quarkx.setupsubset()
  237. #        if setup["NoMapChecks"]!="1":
  238. #            import mapsearch
  239. #            if mapsearch.CheckMap() == 0:
  240. #                return
  241.     if m.info["RunGame"]:
  242.         editor.layout.closeOpenGL()
  243.     RebuildAndRun([(editor.fileobject, editor.Root, m.info)], editor,
  244.       m.info["RunGame"], m.text, 0, [], "", None)
  245.  
  246.  
  247. def RebuildAndRun(maplist, editor, runquake, text, forcepak, extracted, cfgfile, defaultbsp):
  248.  
  249.     #
  250.     # Turn the "extracted" to lowercase.
  251.     #
  252.     for i in range(len(extracted)):
  253.         extracted[i] = extracted[i].lower()
  254.  
  255.     #
  256.     # First, extract all textures and compute .map file names.
  257.     #
  258.     if editor is None:
  259.         texsrc = None
  260.     else:
  261.         texsrc = editor.TexSource
  262.  
  263.     setup = quarkx.setupsubset()
  264.     newlist = []
  265.     textures = {}
  266.     texwarning = 0
  267.     texwarninglist = ""
  268.     gameneedwad = setup["GameNeedWad"]
  269.  
  270.  
  271.     for mapfileobject, root, buildmode in maplist:
  272.  
  273.         if buildmode["ExportMapFile"]:
  274.             if MapOption("AutoCheckMap", SS_MAP):
  275.                 setup = quarkx.setupsubset()
  276.                 if setup["NoMapChecks"]!="1":
  277.                     import mapsearch
  278.                     if mapsearch.CheckMap() == 0:
  279.                         return
  280.  
  281.         map = checkfilename(mapfileobject["FileName"] or mapfileobject.shortname).lower()
  282.         mapinfo = {"map": map}
  283.         if buildmode["ExportMapFile"] \
  284.         or buildmode["BuildPgm1"] \
  285.         or buildmode["BuildPgm2"] \
  286.         or buildmode["BuildPgm3"] \
  287.         or buildmode["BuildPgm4"] \
  288.         or buildmode["BuildPgm5"] \
  289.         or buildmode["BuildPgm6"] \
  290.         or buildmode["BuildPgm7"] \
  291.         or buildmode["BuildPgm8"] \
  292.         or buildmode["BuildPgm9"]:
  293.             bspfile = quarkx.outputfile("maps/%s.bsp" % map)
  294.             if bspfile in extracted:
  295.                 continue
  296.             extracted = extracted + filesformap(map)
  297.             newlist.append((mapfileobject, root, buildmode, mapinfo))
  298.         #
  299.         # Find textures used in map
  300.         #
  301.         if buildmode["Textures"] or gameneedwad:
  302.             list2 = quarkx.texturesof([root])
  303.         if gameneedwad:
  304.             texwad = "%s.wad" % map
  305.             list = []
  306.             wadlist = {}
  307.             for t in list2:
  308.                 t1 = quarkx.loadtexture(t)
  309.                 if t1 is None:
  310.                     texwarning = texwarning + 1
  311.                     if len(texwarninglist):
  312.                         texwarninglist = texwarninglist + ", "
  313.                     texwarninglist = texwarninglist + "%s" % t
  314.                 elif (t1.type == '.wl') and t1["h"]:        # Half-Life texture link
  315.                     wadlist["../"+t1["s"]+"/"+t1["d"]+".wad"] = None
  316.                 else:
  317.                     list.append(t)
  318.             list2 = list
  319.             if len(list2):
  320.                 wadlist[texwad] = None
  321.             mapinfo["wad"] = ';'.join(wadlist.keys())
  322.         else:
  323.             texwad = setup["TextureWad"]
  324.             mapinfo["wad"] = texwad
  325.         if buildmode["Textures"] and len(list2):
  326.             try:       # put the textures in the list of textures to extract
  327.                 texlist = textures[texwad]
  328.             except:
  329.                 texlist = []
  330.                 textures[texwad] = texlist
  331.             for t in list2:
  332.                 if not (t in texlist):
  333.                     texlist.append(t)
  334.  
  335.     if texwarning:
  336.         errtext = Strings[-103] % texwarning
  337.         errtext = errtext + "\n\n" + texwarninglist
  338.         if quarkx.msgbox(errtext, MT_WARNING, MB_OK_CANCEL) != MR_OK:
  339.             return
  340.  
  341.     texcount = None
  342.     for texwad, texlist in textures.items():
  343.         if gameneedwad:
  344.             setup["TextureWad"] = texwad
  345.         list2 = quarkx.maptextures(texlist, 2, texsrc)    # extract the textures
  346.         texlist = len(texlist)
  347.         list2 = len(list2)
  348.         if texcount is not None:
  349.             texlist = texlist + texcount[0]
  350.             list2 = list2 + texcount[1]
  351.         texcount = (texlist, list2)
  352.  
  353.     if gameneedwad:
  354.         setup["TextureWad"] = "?"
  355.     if texcount is None:    # extract at least the base files
  356.         quarkx.maptextures([], 2)
  357.  
  358.     #
  359.     # Precompute a few variables.
  360.     #
  361.     tmpquark = quarkx.outputfile("")
  362.     if tmpquark[-1]=='\\':
  363.         tmpquark = tmpquark[:-1]
  364.     consolecloser = CloseConsole()   # close or reopens the console at the end
  365.     consolecloser.console = len(maplist) and maplist[-1][2]["Pause"]
  366.     next = consolecloser
  367.     missing = ""
  368.     hxstr = ""
  369.     hxstrfile = setup["HxStrings"]
  370.     if hxstrfile and len(maplist):
  371.         try:
  372.             hxstr = quarkx.needgamefile(hxstrfile)["Data"]
  373.             extracted.append(hxstrfile.lower())
  374.         except:
  375.             pass
  376.  
  377.     if runquake or len(extracted):
  378.         if runquake:    # if we have to run the game
  379.             if defaultbsp:
  380.                 map = defaultbsp
  381.             elif len(newlist):
  382.                 map = newlist[0][3]["map"]
  383.             elif len(maplist)==1:
  384.                 map = mapinfo["map"]
  385.             else:
  386.                 map = qquake.GameConsole.NO_MAP
  387.                 cfgfile = cfgfile + "echo\necho \"No map to begin with.\"\necho \"To choose a map, type: map <filename>\"\n"
  388.         else:
  389.             map = qquake.GameConsole.DONT_RUN
  390.         next = qquake.GameConsole(map, extracted, cfgfile, forcepak, next)
  391.  
  392.     #
  393.     # Loop through the maps to rebuild.
  394.     #
  395.  
  396.     newlist.reverse()
  397.     for mapfileobject, root, buildmode, mapinfo in newlist:
  398.  
  399.         map = mapinfo["map"]
  400.         bspfile = quarkx.outputfile("./maps/%s.bsp" % map)
  401.  
  402.         if setup["StupidBuildToolKludge"]:
  403.             # stupid tool that wants to run in the base dir
  404.             toolworkdir = setup["Directory"] + "/" + setup["BaseDir"]
  405.             argument_mappath = "../tmpquark/maps"
  406.             argument_mapfile = "../tmpquark/maps/%s.map" % map
  407.             argument_file    = "../tmpquark/maps/%s" % map
  408.         else:
  409.             # clever tool that can run anywhere
  410.             toolworkdir = tmpquark
  411.             argument_mappath = "./maps"
  412.             argument_mapfile = "./maps/%s.map" % map
  413.             argument_file    = "./maps/%s" % map
  414.  
  415.         for pgrmnbr in range(9,0,-1):
  416.             pgrmx = "BuildPgm%d" % pgrmnbr
  417.  
  418.             if buildmode[pgrmx]:        # Should this program be run?
  419.                 cmdline = setup[pgrmx]
  420.  
  421.                 console = BuildPgmConsole_Advanced
  422.  
  423.                 # Check first Default build-tool directory
  424.                 try:
  425.                     if setup["BuildPgmsDir"] is None:
  426.                        cmdline2 = cmdline
  427.                     else:
  428.                        cmdline2 = setup["BuildPgmsDir"] + "\\" + cmdline
  429.                     if (not quarkx.getfileattr(cmdline2)==FA_FILENOTFOUND):
  430.                         # Success, use this build-tool!
  431.                         cmdline = cmdline2
  432.  
  433.                 except:
  434.                     pass
  435.  
  436.                 if (not cmdline) or (quarkx.getfileattr(cmdline)==FA_FILENOTFOUND):
  437.                     desc = setup["BuildDesc%d" % pgrmnbr] or cmdline or pgrmx
  438.                     missing = "     %s\n%s" % (desc, missing)
  439.                 else:
  440.                     # Prepare to run this program
  441.                     cmdline = '"%s"' % cmdline
  442.                     pgrmcmd = "BuildArgs%d" % pgrmnbr
  443.  
  444.                     # Create list of file-extensions to check for existance/non-existance after build
  445.                     checkextensions = []
  446.                     p1 = setup["BuildCheck%d" % pgrmnbr]
  447.                     if p1: checkextensions = CreateCheckFileExtensionArray(p1)
  448.  
  449.                     # Fixed command-line arguments
  450.                     p1 = setup[pgrmcmd]
  451.                     if p1: cmdline = cmdline + " " + p1
  452.  
  453.                     # Additional command-line arguments
  454.                     p1 = buildmode[pgrmcmd]
  455.                     if p1: cmdline = cmdline + " " + p1
  456.  
  457.                     # Search and replace any user-variable
  458.                     newcmdline = cmdline
  459.                     newcmdline = newcmdline.replace("%mappath%",  argument_mappath)
  460.                     newcmdline = newcmdline.replace("%mapfile%",  argument_mapfile)
  461.                     newcmdline = newcmdline.replace("%file%",     argument_file)
  462.                     newcmdline = newcmdline.replace("%basepath%", setup["Directory"])
  463.                     newcmdline = newcmdline.replace("%quarkpath%", quarkx.exepath)
  464.                     if setup["BuildPgmsDir"] is not None:
  465.                        newcmdline = newcmdline.replace("%buildpgmsdir%", setup["BuildPgmsDir"])
  466.                     newcmdline = newcmdline.replace("%output%", quarkx.outputfile())
  467.  
  468. #                    debug('mappath: '+argument_mappath)
  469. #                    debug('mapfile: '+argument_mapfile)
  470. #                    debug('file: '+argument_file)
  471. #                    debug('basepath: '+setup["Directory"])
  472. #                    debug('output: '+quarkx.outputfile())
  473.  
  474.                     # If user-variable were not replaced, automatically append map-filename
  475.                     if (newcmdline == cmdline):
  476.                         cmdline = cmdline + " " + argument_mapfile
  477.                     else:
  478.                         cmdline = newcmdline
  479.  
  480.                     # Put this build-program last in execution queue
  481.                     next = console(cmdline, toolworkdir, bspfile, editor, next, checkextensions)
  482.  
  483.         if missing:
  484.             msg = "%s\n%s" % (missing, Strings[5586])
  485.             if quarkx.msgbox(msg, MT_CONFIRMATION, MB_YES | MB_NO) == MR_YES:
  486.                 quarkx.openconfigdlg(":")
  487.             return
  488.  
  489.         if buildmode["ExportMapFile"]:
  490.             hxstr = writemapfile(root, map, buildmode["SelOnly"], mapinfo["wad"], hxstr)
  491.  
  492.     if hxstr:
  493.         hxf = quarkx.newfileobj("hxstr.txt")
  494.         hxf["Data"] = hxstr
  495.         del hxstr
  496.         hxf.savefile(quarkx.outputfile(hxstrfile))
  497.         del hxf
  498.  
  499.     #
  500.     # AutoSave
  501.     #
  502.     if quarkx.setupsubset(SS_MAP, "Building")["AutoSaveRun"] and editor is not None:
  503.         editor.AutoSave()
  504.  
  505.     #
  506.     # Run the above queued programs in the console.
  507.     #
  508.  
  509.     if next is not consolecloser:
  510.         print
  511.         str = " " + filter(lambda c: c!="&", text) + " "
  512.         l = (79-len(str))/2
  513.         if l>0:
  514.             str = "_"*l + str + "_"*l
  515.         print str
  516.         print
  517.         if qquake.BuildConsole():
  518.             quarkx.console()
  519.         next.run()    # do it !
  520.  
  521.     elif texcount is not None:
  522.         target = setup["TextureWad"] or setup["TexturesPath"]
  523. #        quarkx.msgbox(target,2,4)
  524.         target = quarkx.outputfile(target)
  525. #        quarkx.msgbox(target,2,4)
  526.         c1,c2 = texcount
  527.         if c1<c2:
  528.             msg = Strings[5590] % (c2, target, c2-c1)
  529.         else:
  530.             msg = Strings[5589] % (c2, target)
  531.         quarkx.msgbox(msg, MT_INFORMATION, MB_OK)
  532.  
  533.     else:
  534.         quarkx.msgbox(Strings[5653], MT_INFORMATION, MB_OK)
  535.  
  536.  
  537. def Customize1Click(mnu):
  538.     editor = mapeditor(SS_MAP)
  539.     if editor is None: return
  540.     setup = quarkx.setupsubset()
  541.     if setup["SpecialCustomQuakeMenu"]:
  542.         form1 = setup["SpecialCustomQuakeMenu"]
  543.     else:
  544.         form1 = "CustomQuakeMenu"
  545.     gamename = setup.shortname
  546.     group = quarkx.newobj("%s menu:config"%gamename)
  547.     sourcename = "UserData %s.qrk" % gamename
  548.     file = LoadPoolObj(sourcename, quarkx.openfileobj, sourcename)
  549.     ud = file.findname("Menu.qrk")
  550.     for p in ud.subitems:
  551.         txt = p["Txt"]
  552.         ci = quarkx.newobj("%s.toolbar"%txt)
  553.         ci.copyalldata(p)
  554.         ci["Form"] = (form1, "CustomQuakeMenuSep")[txt=="-"]
  555.         group.appenditem(ci)
  556.     #explorer.addroot(group)
  557.     newitem = quarkx.newobj("menu item.toolbar")
  558.     newitem[";desc"] = "create a new menu item"
  559.     newitem["Form"] = form1
  560.     newsep = quarkx.newobj("-.toolbar")
  561.     newsep[";desc"] = "create a new separator"
  562.     newsep["Form"] = "CustomQuakeMenuSep"
  563.     if quarkx.openconfigdlg("Customize %s menu" % gamename, group, [newsep, newitem]):
  564.         for i in range(ud.itemcount-1, -1, -1):
  565.             ud.removeitem(i)
  566.         for ci in group.subitems:
  567.             p = quarkx.newobj("item:")
  568.             p.copyalldata(ci)
  569.             p["Form"] = None
  570.             p["Txt"] = ci.shortname
  571.             ud.appenditem(p)
  572.         editor.initmenu(quarkx.clickform)
  573.         file.savefile()
  574.  
  575.  
  576. def loadLeakFile(m):
  577.     import mapholes
  578.     mapholes.LoadLinFile(m.editor, m.auxfilename)
  579.         
  580. leakMenuItem = qmenu.item("Load Leak&file",loadLeakFile,hint="|Loads the leak file, if there is one.\n\nYou are responsible for making sure that the leak file actually belongs to the map you're working on (the build tools will delete previous leak files after a successful compile, but it is still possible to get confused, if you start a new map with the same name as an older one with a leak).\n\nThe thickness of the 'Leak line' that will be drawn can be changed by going to the 'Options' menu and selecting the 'Set Line Thickness' function.|intro.mapeditor.menu.html#gamemenu")
  581.  
  582.  
  583. def loadPortalFile(m):
  584.     import mapportals
  585.     mapportals.LoadPortalFile(m.editor, m.auxfilename)
  586.         
  587. portalsMenuItem = qmenu.item("Load Portal&file",loadPortalFile,hint="|Loads the portals file, if there is one.\n\nWhat the blue lines indicate is the 'windows' between the convex ('leaf nodes') that the bsp process carves the visible spaces of your map into. So you can investigate the effects of using detail and hint-brushes, etc to make your map more efficient and run better.\n\nYou are responsible for making sure that the portals (probably .prt) file actually belongs to the map you're working on, and are up-to-date.|intro.mapeditor.menu.html#gamemenu")
  588.  
  589. def prepAuxFileMenuItem(item,extkey,defext):
  590.     editor=item.editor
  591.     mapfileobject = editor.fileobject
  592.     map = checkfilename(mapfileobject["FileName"] or mapfileobject.shortname).lower()
  593.     mapfilename = quarkx.outputfile('')+'maps\\'+map
  594.     auxextension = quarkx.setupsubset()[extkey]
  595.     if not auxextension:
  596.         auxextension=defext
  597.     auxfilename = mapfilename+auxextension
  598.     if quarkx.getfileattr(auxfilename)==FA_FILENOTFOUND:
  599.         item.state = qmenu.disabled
  600.     else:
  601.         item.state = qmenu.normal
  602.         item.editor = editor
  603.         item.auxfilename = auxfilename
  604.  
  605. import mapbrushnum
  606.  
  607. def BrushNumClick(m):
  608.     import mapbrushnum
  609.     mapbrushnum.LoadBrushNums(m.editor, m.auxfilename)
  610.     
  611. brushnumsMenuItem = qmenu.item("Select Brush Number",BrushNumClick,"|Select Brush Number:\n\nTries to find brushes by number, as specified in compile tool error messages (the use of duplicators, etc. might subvert this).\n\nSee the infobase for more detailed explanations on how to use this function.|maped.builderrors.console.html")
  612.  
  613. def onclick(m):
  614.     for args in ((leakMenuItem,"MapHoles",".lin"),
  615.                  (portalsMenuItem,"MapPortals",".prt"),
  616.                  (brushnumsMenuItem,"MapFileExt",".map"), # this options keyword doesn't exist
  617.                  ):
  618.       apply(prepAuxFileMenuItem,args)
  619.  
  620. def QuakeMenu(editor):
  621.     "The Quake menu, with its shortcuts."
  622.  
  623.      # this menu is read from UserData.qrk.
  624.  
  625.     items = []
  626.     sc = {}
  627.     isbsp = "Bsp" in editor.fileobject.classes   # some items don't apply for BSP files
  628.     gamename = quarkx.setupsubset().shortname
  629.     #firstcmd = FirstBuildCmd()
  630.     sourcename = "UserData %s.qrk" % gamename
  631.     ud = LoadPoolObj(sourcename, quarkx.openfileobj, sourcename)
  632.     ud = ud.findname("Menu.qrk")
  633.     if ud is not None:
  634.         for p in ud.subitems:
  635.             txt = p["Txt"]
  636.             if txt=="-":
  637.                 items.append(qmenu.sep)
  638.             else:
  639.                 m = qmenu.item(txt, qmenuitem1click, "|The commands in this menu lets you run your map with the game. The most common commands are the first few ones, which lets you try your map as a one-step operation.\n\nBefore a map can be played, it must be compiled (translated into a .bsp file). This is done by other programs that QuArK will call for you. See the Configuration dialog box, under the page of the game you wish to map for, where you must tell QuArK where these build programs are installed. The programs themselves are available in Build Packs, one for each game you want to make maps for, and that can be downloaded from http://dynamic.gamespy.com/~quark/.|intro.mapeditor.menu.html#gamemenu")
  640.                 m.info = p
  641.                 #if isbsp and p[firstcmd]:
  642.                 #    m.state = qmenu.disabled
  643.                 #elif p["Shortcut"]:
  644.                 if p["Shortcut"]:
  645.                     sc[p["Shortcut"]] = m
  646.                 items.append(m)
  647.         items.append(qmenu.sep)
  648.         for item in (leakMenuItem, portalsMenuItem, brushnumsMenuItem):
  649.             item.editor=editor
  650.             items.append(item)
  651.         items.append(qmenu.sep)
  652.         items.append(qmenu.item("&Customize menu...", Customize1Click, "customizes this menu"))
  653.     Quake1 = qmenu.popup("&"+gamename, items, onclick)
  654.     Quake1.state = not len(items) and qmenu.disabled
  655.     return Quake1, sc
  656.  
  657.  
  658. import mapportals
  659.  
  660. # ----------- REVISION HISTORY ------------
  661. #
  662. #$Log: mapquakemenu.py,v $
  663. #Revision 1.37  2003/12/17 13:58:59  peter-b
  664. #- Rewrote defines for setting Python version
  665. #- Removed back-compatibility with Python 1.5
  666. #- Removed reliance on external string library from Python scripts
  667. #
  668. #Revision 1.36  2003/03/28 16:09:23  cdunde
  669. #More infobase updates
  670. #
  671. #Revision 1.35  2003/03/27 20:35:48  cdunde
  672. #Update info and links to infobase.
  673. #
  674. #Revision 1.34  2003/03/24 10:34:24  tiglari
  675. #support for brush-number finder
  676. #
  677. #Revision 1.33  2003/03/21 05:56:26  cdunde
  678. #Update infobase and add links
  679. #
  680. #Revision 1.32  2003/03/19 22:27:58  tiglari
  681. #change default holes file to .lin
  682. #
  683. #Revision 1.31  2003/03/19 11:24:32  tiglari
  684. #expand help for portal view command
  685. #
  686. #Revision 1.30  2003/03/19 11:06:54  tiglari
  687. #add commands for loading leak (pts/lin) and portal (prt) files
  688. #
  689. #Revision 1.29  2003/03/17 00:11:05  tiglari
  690. #Add manual leak file loading command
  691. #
  692. #Revision 1.28  2003/01/06 22:24:02  tiglari
  693. #check leak files for having actual content before registering build error
  694. #
  695. #Revision 1.27  2002/08/09 10:01:45  decker_dk
  696. #Fixed problem, when "warning about missing textures and do you want to continue"
  697. #never continued regarding pressing OK or Cancel. The if-statement checked for MR_YES
  698. #and not MR_OK.
  699. #
  700. #Revision 1.26  2002/05/07 09:13:02  tiglari
  701. #prevent error when no default dir for buildpgms is specified (diagnosis and fix by nurail)
  702. #
  703. #Revision 1.25  2002/04/28 11:41:32  tiglari
  704. #New command line argument substitutions (for RTCW)
  705. #
  706. #Revision 1.24  2002/03/26 22:19:20  tiglari
  707. #support UseIntegralVertexes flag
  708. #
  709. #Revision 1.23  2002/02/05 18:33:15  decker_dk
  710. #Added a %basepath% command-line replacement variable.
  711. #
  712. #Revision 1.22  2001/09/24 22:24:27  tiglari
  713. #checks moved into RebuildandRun, made conditional on ExportMapFile
  714. #
  715. #Revision 1.21  2001/07/24 02:42:40  tiglari
  716. #.hmf extension when 6dx maps committed
  717. #
  718. #Revision 1.20  2001/07/19 12:00:17  tiglari
  719. #support disabling mapchecks in game config files
  720. #
  721. #Revision 1.19  2001/03/18 12:17:26  decker_dk
  722. #Fixed FindSingleExtension() so it also reads the last extension at end-of-line.
  723. #
  724. #Revision 1.18  2001/03/15 20:53:53  tiglari
  725. #fix for no action build control parameters (Q1/H2)
  726. #
  727. #Revision 1.17  2001/03/14 19:20:49  decker_dk
  728. #Functionality for '-ext{action}'... which is not documented yet!
  729. #
  730. #Revision 1.16  2001/03/12 15:31:39  tiglari
  731. #Hacked in linfile loading. Assumes that .lin/.pts is the only must-not-exist file,
  732. #  which is true for now, but prolly not reliable.  better fix wanted
  733. #
  734. #Revision 1.15  2001/02/07 00:08:33  aiv
  735. #added fixes from 6.1c release
  736. #
  737. #Revision 1.14  2001/01/27 18:24:39  decker_dk
  738. #Renamed the key 'Q2TexPath' to 'TexturesPath'.
  739. #
  740. #Revision 1.13  2000/10/28 19:29:38  decker_dk
  741. #Correctly export .MAP file, even if no build-tool is marked for execution
  742. #
  743. #Revision 1.12  2000/10/26 18:15:45  tiglari
  744. #Enable Brush Primitives support
  745. #
  746. #Revision 1.11  2000/10/19 19:00:42  decker_dk
  747. #Fix if 'BuildPgmsDir' was not filled out
  748. #
  749. #Revision 1.10  2000/10/09 18:18:02  decker_dk
  750. #Build-Tool Controllers
  751. #
  752. #Revision 1.9  2000/07/24 23:58:11  alexander
  753. #added: .lin file processing for bspc leaks
  754. #
  755. #Revision 1.8  2000/07/03 14:10:50  alexander
  756. #fixed: removed unnecessary dialogs when extract textures
  757. #
  758. #Revision 1.7  2000/06/07 22:29:19  alexander
  759. #changed: use the setup entry "SpecialCustomQuakeMenu" instead of
  760. #         the NEEDQCSG flag to select a form for custom quake menus
  761. #fixed: check now if aas file was built at all
  762. #
  763. #Revision 1.6  2000/06/05 00:11:27  alexander
  764. #fixed history
  765. #
  766. #Revision 1.5  2000/06/05 00:09:49  alexander
  767. #added: kludge for stupid tools (like those of SoF) that require to run in the games base dir)
  768. #
  769. #Revision 1.4  2000/06/04 21:41:29  alexander
  770. #added: bspc console class, support for running the bsp to aas converter for bots in q3
  771. #
  772. #Revision 1.3  2000/06/02 16:00:22  alexander
  773. #added cvs headers
  774. #
  775. #
  776. #
  777.